Passed
Pull Request — master (#195)
by
unknown
08:51
created

FileSaver.js ➔ click   A

Complexity

Conditions 2

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
c 0
b 0
f 0
dl 0
loc 9
rs 10
1
(function (global, factory) {
2
  if (typeof define === "function" && define.amd) {
0 ignored issues
show
Bug introduced by
The variable define seems to be never declared. If this is a global, consider adding a /** global: define */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
3
    define([], factory);
4
  } else if (typeof exports !== "undefined") {
5
    factory();
6
  } else {
7
    var mod = {
8
      exports: {}
9
    };
10
    factory();
11
    global.FileSaver = mod.exports;
12
  }
13
})(this, function () {
14
  "use strict";
15
16
  /*
17
  * FileSaver.js
18
  * A saveAs() FileSaver implementation.
19
  *
20
  * By Eli Grey, http://eligrey.com
21
  *
22
  * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
23
  * source  : http://purl.eligrey.com/github/FileSaver.js
24
  */
25
  // The one and only way of getting global scope in all environments
26
  // https://stackoverflow.com/q/3277182/1008999
27
  var _global = typeof window === 'object' && window.window === window ? window : typeof self === 'object' && self.self === self ? self : typeof global === 'object' && global.global === global ? global : void 0;
0 ignored issues
show
Bug introduced by
The variable self seems to be never declared. If this is a global, consider adding a /** global: self */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
28
29
  function bom(blob, opts) {
30
    if (typeof opts === 'undefined') opts = {
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
31
      autoBom: false
32
    };else if (typeof opts !== 'object') {
33
      console.warn('Deprecated: Expected third argument to be a object');
34
      opts = {
35
        autoBom: !opts
36
      };
37
    } // prepend BOM for UTF-8 XML and text/* types (including HTML)
38
    // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
39
40
    if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
41
      return new Blob([String.fromCharCode(0xFEFF), blob], {
0 ignored issues
show
Bug introduced by
The variable Blob seems to be never declared. If this is a global, consider adding a /** global: Blob */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
42
        type: blob.type
43
      });
44
    }
45
46
    return blob;
47
  }
48
49
  function download(url, name, opts) {
50
    var xhr = new XMLHttpRequest();
51
    xhr.open('GET', url);
52
    xhr.responseType = 'blob';
53
54
    xhr.onload = function () {
55
      saveAs(xhr.response, name, opts);
56
    };
57
58
    xhr.onerror = function () {
59
      console.error('could not download file');
60
    };
61
62
    xhr.send();
63
  }
64
65
  function corsEnabled(url) {
66
    var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker
67
68
    xhr.open('HEAD', url, false);
69
70
    try {
71
      xhr.send();
72
    } catch (e) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
73
74
    return xhr.status >= 200 && xhr.status <= 299;
75
  } // `a.click()` doesn't work for all browsers (#465)
76
77
78
  function click(node) {
79
    try {
80
      node.dispatchEvent(new MouseEvent('click'));
0 ignored issues
show
Bug introduced by
The variable MouseEvent seems to be never declared. If this is a global, consider adding a /** global: MouseEvent */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
81
    } catch (e) {
82
      var evt = document.createEvent('MouseEvents');
83
      evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null);
84
      node.dispatchEvent(evt);
85
    }
86
  } // Detect WebView inside a native macOS app by ruling out all browsers
87
  // We just need to check for 'Safari' because all other browsers (besides Firefox) include that too
88
  // https://www.whatismybrowser.com/guides/the-latest-user-agent/macos
89
90
91
  var isMacOSWebView = /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent);
0 ignored issues
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
92
  var saveAs = _global.saveAs || ( // probably in some web worker
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable saveAs already seems to be declared on line 93. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
93
  typeof window !== 'object' || window !== _global ? function saveAs() {}
94
  /* noop */
95
  // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView
96
  : 'download' in HTMLAnchorElement.prototype && !isMacOSWebView ? function saveAs(blob, name, opts) {
0 ignored issues
show
Bug introduced by
The variable HTMLAnchorElement seems to be never declared. If this is a global, consider adding a /** global: HTMLAnchorElement */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
97
    var URL = _global.URL || _global.webkitURL;
98
    var a = document.createElement('a');
99
    name = name || blob.name || 'download';
100
    a.download = name;
101
    a.rel = 'noopener'; // tabnabbing
102
    // TODO: detect chrome extensions & packaged apps
103
    // a.target = '_blank'
104
105
    if (typeof blob === 'string') {
106
      // Support regular links
107
      a.href = blob;
108
109
      if (a.origin !== location.origin) {
110
        corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank');
0 ignored issues
show
Bug introduced by
The call to click seems to have too many arguments starting with a.target = "_blank".
Loading history...
111
      } else {
112
        click(a);
113
      }
114
    } else {
115
      // Support blobs
116
      a.href = URL.createObjectURL(blob);
117
      setTimeout(function () {
118
        URL.revokeObjectURL(a.href);
119
      }, 4E4); // 40s
120
121
      setTimeout(function () {
122
        click(a);
123
      }, 0);
124
    }
125
  } // Use msSaveOrOpenBlob as a second approach
126
  : 'msSaveOrOpenBlob' in navigator ? function saveAs(blob, name, opts) {
127
    name = name || blob.name || 'download';
128
129
    if (typeof blob === 'string') {
130
      if (corsEnabled(blob)) {
131
        download(blob, name, opts);
132
      } else {
133
        var a = document.createElement('a');
134
        a.href = blob;
135
        a.target = '_blank';
136
        setTimeout(function () {
137
          click(a);
138
        });
139
      }
140
    } else {
141
      navigator.msSaveOrOpenBlob(bom(blob, opts), name);
0 ignored issues
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
142
    }
143
  } // Fallback to using FileReader and a popup
144
  : function saveAs(blob, name, opts, popup) {
145
    // Open a popup immediately do go around popup blocker
146
    // Mostly only available on user interaction and the fileReader is async so...
147
    popup = popup || open('', '_blank');
148
149
    if (popup) {
150
      popup.document.title = popup.document.body.innerText = 'downloading...';
151
    }
152
153
    if (typeof blob === 'string') return download(blob, name, opts);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
154
    var force = blob.type === 'application/octet-stream';
155
156
    var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari;
157
158
    var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent);
0 ignored issues
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
159
160
    if ((isChromeIOS || force && isSafari || isMacOSWebView) && typeof FileReader !== 'undefined') {
0 ignored issues
show
Bug introduced by
The variable FileReader seems to be never declared. If this is a global, consider adding a /** global: FileReader */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
161
      // Safari doesn't allow downloading of blob URLs
162
      var reader = new FileReader();
163
164
      reader.onloadend = function () {
165
        var url = reader.result;
166
        url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;');
167
        if (popup) popup.location.href = url;else location = url;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
168
        popup = null; // reverse-tabnabbing #460
169
      };
170
171
      reader.readAsDataURL(blob);
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
172
    } else {
173
      var URL = _global.URL || _global.webkitURL;
174
      var url = URL.createObjectURL(blob);
175
      if (popup) popup.location = url;else location.href = url;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
176
      popup = null; // reverse-tabnabbing #460
177
178
      setTimeout(function () {
179
        URL.revokeObjectURL(url);
180
      }, 4E4); // 40s
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
181
    }
182
  });
183
  _global.saveAs = saveAs.saveAs = saveAs;
184
185
  if (typeof module !== 'undefined') {
186
    module.exports = saveAs;
187
  }
188
});
189